#include "qabstracthost.h"

#include "../property/qabstractproperty.h"
#include "../shared/xmlobject.h"

#include <QVariant>
#include <QUuid>

QAbstractHost::QAbstractHost(QAbstractHost *parent) :
    QObject(parent),
    m_parent(parent),
    m_object(NULL)
{
    set_attribute("uuid",QUuid::createUuid().toString());

    if(m_parent!=NULL)
    {
        m_parent->m_children.append(this);
    }
}

QAbstractHost::~QAbstractHost()
{
    clear();
    if(m_parent!=NULL)
    {
        m_parent->m_children.removeAll(this);
    }
    if(m_object!=NULL)
    {
        m_object->deleteLater();
    }
}

void QAbstractHost::clear()
{
    while(m_children.size()>0)
    {
        delete m_children.first();
    }
}

QString QAbstractHost::get_object_type()
{
    return "";
}

QString QAbstractHost::get_show_name()
{
    return "";
}

QString QAbstractHost::get_show_icon()
{
    return "";
}

QString QAbstractHost::get_show_group()
{
    return "";
}

void QAbstractHost::insert_children(const QList<int> &indexs, const QList<QAbstractHost *> &children)
{
    QList<int> ind;
    QList<QAbstractHost*> list;

    for(int i=0;i<children.size();i++)
    {
        QAbstractHost *h=children.at(i);
        if(h->m_parent!=NULL)
        {
            continue;
        }
        int index=indexs.at(i);
        if(index<0 || index>m_children.size())
        {
            index=m_children.size();
        }
        h->m_parent=this;
        if(h->get_object()->isWidgetType())
        {
            QWidget* w=(QWidget*)h->get_object();
            w->setParent((QWidget*)m_object);
            w->setVisible(true);
        }
        else
        {
            h->get_object()->setParent(m_object);
        }
        m_children.insert(index,h);
        ind.append(index);
        list.append(h);
    }
    emit insert_children_signal(list,ind);
}

void QAbstractHost::remove_children(const QList<QAbstractHost *> &children)
{
    QList<QAbstractHost*> list;

    foreach(QAbstractHost* h,children)
    {
        if(h->m_parent!=this)
        {
            continue;
        }
        list.append(h);
    }

    if(list.size()==0)
    {
        return;
    }
    emit remove_children_signal(list);

    foreach(QAbstractHost* h,list)
    {
        h->m_parent=NULL;
        if(h->m_object->isWidgetType())
        {
            QWidget* w=(QWidget*)h->m_object;
            w->setParent(NULL);
            w->setVisible(false);
        }
        else
        {
            h->m_object->setParent(NULL);
        }
        m_children.removeAll(h);
    }
}

QObject* QAbstractHost::get_object()
{
    return m_object;
}

void QAbstractHost::create_object()
{
}

void QAbstractHost::init()
{
    create_object();
    init_property();

    if(m_object!=NULL)
    {
        m_object->installEventFilter(this);
        foreach(QAbstractProperty* pro,m_propertys)
        {
            pro->set_value(m_object->property(pro->get_property("name").toByteArray()));
        }
    }

}

void QAbstractHost::init_property()
{
}

void QAbstractHost::set_parent(QAbstractHost *parent, int index)
{
    if(m_parent==parent)
    {
        return;
    }
    if(m_parent!=NULL)
    {
        m_parent->m_children.removeAll(this);
    }

    m_parent=parent;
    if(m_parent!=NULL)
    {
        if(index<0 || index>parent->m_children.size())
        {
            index=m_children.size();
        }
        m_parent->m_children.insert(index,this);
        if(m_object->isWidgetType())
        {
            QWidget* wid=(QWidget*)m_object;
            wid->setParent((QWidget*)parent->m_object);
            wid->setVisible(true);
        }
        else
        {
            m_object->setParent(parent->m_object);
        }
    }
    else
    {
        if(m_object->isWidgetType())
        {
            QWidget* wid=(QWidget*)m_object;
            wid->setParent(NULL);
        }
        else
        {
            m_object->setParent(NULL);
        }
    }
    emit parent_changed();
}

QList<QAbstractHost*>   QAbstractHost::get_children()
{
    return m_children;
}

QAbstractHost* QAbstractHost::get_child(int index)
{
    if(index<0 || index>=m_children.size())
    {
        return NULL;
    }
    else
    {
        return m_children.at(index);
    }
}

QAbstractHost* QAbstractHost::get_parent()
{
    return m_parent;
}

int QAbstractHost::get_child_count()
{
    return m_children.size();
}

QAbstractProperty* QAbstractHost::get_property(const QString &name)
{
    QStringList list=name.split(".");
    if(list.size()>=0)
    {
        QAbstractProperty* pro=m_nameToProperty.value(list.takeFirst());
        while(list.size()>0)
        {
            pro=pro->get_child(list.takeFirst());
            if(pro==NULL)
            {
                break;
            }
        }
        return pro;
    }
    return NULL;
}

QList<QAbstractProperty*> QAbstractHost::get_propertys()
{
    return m_propertys;
}

QVariant QAbstractHost::get_property_value(const QString &name)
{
    QAbstractProperty *pro=get_property(name);
    if(pro!=NULL)
    {
        return pro->get_value();
    }
    else
    {
        return QVariant();
    }
}

void QAbstractHost::set_property_value(const QString &name, const QVariant &value)
{
    QAbstractProperty *pro=get_property(name);
    if(pro!=NULL)
    {
        pro->set_value(value);
        QAbstractProperty *p=pro;
        while(p->get_parent()!=NULL)
        {
            p=p->get_parent();
        }
        m_object->setProperty(p->get_property("name").toByteArray(),p->get_value());
    }
}

void QAbstractHost::set_attribute(const QString &key, const QString &value)
{
    m_attributes.insert(key,value);
}

QString QAbstractHost::get_attribute(const QString &key)
{
    return m_attributes.value(key);
}

void QAbstractHost::set_default()
{
    foreach(QAbstractProperty* pro,m_propertys)
    {
        pro->set_default();
        if(m_object!=NULL)
        {
            m_object->setProperty(pro->get_property("name").toByteArray(),pro->get_value());
        }
    }
    foreach(QAbstractHost* h,m_children)
    {
        h->set_default();
    }
}

QAction* QAbstractHost::get_action(const QString &name)
{
    return m_nameToAction.value(name);
}

QList<QAction*> QAbstractHost::get_actions()
{
    return m_actions;
}

void QAbstractHost::insert_action(const QString &name, QAction *ac, int index)
{
    if(m_actions.contains(ac))
    {
        return;
    }

    if(index<0 || index>=m_actions.size())
    {
        index=m_actions.size();
    }

    m_actions.insert(index,ac);
    m_nameToAction.insert(name,ac);
}

void QAbstractHost::remove_action(const QString &name)
{
    QAction* ac=m_nameToAction.value(name);
    m_nameToAction.remove(name);
    if(ac!=NULL)
    {
        m_actions.removeAll(ac);
        delete ac;
    }
}

void QAbstractHost::to_object(XMLObject *xml)
{
    if(xml!=NULL)
    {
        xml->clear();

        xml->set_title(property("title").toString());


        QMapIterator<QString,QString>       it(m_attributes);
        while(it.hasNext())
        {
            it.next();
            xml->set_property(it.key(),it.value());
        }

        XMLObject* obj;
        foreach(QAbstractProperty* pro,m_propertys)
        {
            if(pro->modified() || pro->get_attribute(ATTR_NEEDSAVE).toBool())
            {
                obj=new XMLObject;
                pro->toObject(obj);
                xml->inser_child(-1,obj);
            }
        }

        foreach(QAbstractHost* h,m_children)
        {
            obj=new XMLObject;
            h->to_object(obj);
            xml->inser_child(-1,obj);
        }
    }
}

void QAbstractHost::from_object(XMLObject *xml)
{
    if(xml!=NULL)
    {
        if(xml->get_title()!=property("title").toString())
        {
            return;
        }

        clear();

        QMapIterator<QString,QString>       it(m_attributes);
        while(it.hasNext())
        {
            it.next();
            m_attributes.insert(it.key(),xml->get_property(it.key()));
        }

        if(get_uuid()=="")
        {
            set_uuid(QUuid::createUuid().toString());
        }

        QList<XMLObject*>   children=xml->get_children();
        foreach(XMLObject* obj,children)
        {
            if(obj->get_title()==PROPERTY_TITLE)
            {
                QString name=obj->get_property("name");
                QAbstractProperty *pro=m_nameToProperty.value(name);
                if(pro!=NULL)
                {
                    pro->fromObject(obj);
                    pro->set_attribute(ATTR_NEEDSAVE,true);
                }
            }
            else
            {
                QString name=obj->get_property(HOST_TYPE);

                QAbstractHost *h=QHostFactory::create_host(name);
                if(h!=NULL)
                {
                    h->from_object(obj);
                    h->m_parent=this;
                    if(h->get_object()->isWidgetType())
                    {
                        QWidget* w=(QWidget*)h->get_object();
                        w->setParent((QWidget*)m_object);
                        w->setVisible(true);
                    }
                    else
                    {
                        h->get_object()->setParent(m_object);
                    }
                    m_children.append(h);
                }
            }
        }
    }
}

QString QAbstractHost::get_uuid()
{
    return m_attributes.value("uuid");
}

void QAbstractHost::set_uuid(const QString &uuid)
{
    m_attributes.insert("uuid",uuid);
}

void QAbstractHost::insert_property(QAbstractProperty *property, int index)
{
    if(m_propertys.contains(property))
    {
        return;
    }

    if(index<0 || index>=m_propertys.size())
    {
        index=m_propertys.size();
    }
    property->set_host(this);
    m_propertys.insert(index,property);
    m_nameToProperty.insert(property->get_property("name").toString(),property);
}

void QAbstractHost::remove_property(const QString &name)
{
    QAbstractProperty *pro=m_nameToProperty.value(name);
    m_nameToProperty.remove(name);
    if(pro!=NULL)
    {
        m_propertys.removeAll(pro);
        delete pro;
    }
}

void QAbstractHost::exec(const QString &code, const QMap<QString, QString> &param)
{
}
